home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Our Solar System
/
Our Solar System.iso
/
miscprog
/
librat
/
oprecess.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-31
|
9KB
|
419 lines
/* opreces.c
* Rigorous precession of orbital elements
*
* See euler.txt for explanations.
* Program by Steve Moshier.
*/
#define SALONE 0
double sin(), cos(), zatan2(), fabs();
#define N 3
#if SALONE
double J2000 = 2451545.0; /* 2000 January 1.5 */
double STR = 4.8481368110953599359e-6; /* radians per arc second */
double DTR = 1.7453292519943295769e-2; /* radians per degree */
double RTD = 5.7295779513082320877e1; /* degrees per radian */
double PI = 3.14159265358979323846;
/* Indicate whether input is argument of perihelion (1)
* or longitude of perihelion (0):
*/
#define ARGPERIH 1
main()
{
double JD1, JD2, e[3];
printf( "Enter Julian date of given orbital elements ? " );
scanf( "%lf", &JD1 );
printf( "%.2lf\n", JD1 );
printf( "Julian date of desired orbital elements ? " );
scanf( "%lf", &JD2 );
printf( "%.2lf\n", JD2 );
/* Find the rotation from the ecliptic of JD1 to the orbit.
*/
printf( "Enter longitude of ascending node, in degrees ? " );
scanf( "%lf", &e[0] );
printf( "%.6lf\n", e[0] );
printf( "Inclination ? " );
scanf( "%lf", &e[1] );
printf( "%.6lf\n", e[1] );
#if ARGPERIH
printf( "Arg perihelion ? " );
scanf( "%lf", &e[2] );
#else
printf( "Longitude of the perihelion ? " );
scanf( "%lf", &e[2] );
printf( "%.6lf\n", e[2] );
e[2] -= e[0];
#endif
e[2] *= DTR; /* convert degrees to radians */
e[1] *= DTR;
e[0] *= DTR;
oprecess( JD1, JD2, e );
printf( "\nElements for equinox of %.2lf\n", JD2 );
printf( "Node = %.6lf\n", RTD*e[0] );
printf( "Inclination = %.6lf\n", RTD*e[1] );
printf( "Arg perihelion = %.6lf\n", RTD*e[2] );
printf( "Longitude of the perihelion = %.6lf\n", RTD*(e[2]+e[0]) );
}
/* Matrix transpose.
* B, the output, can occupy the same storage locations as
* A, the input.
*/
mtransp( A, B )
double A[], B[];
{
double x, y;
int r, c, rc, cr;
for( r=0; r<N; r++ )
{
for( c=0; c<=r; c++ )
{
rc = N*r+c;
cr = N*c+r;
x = A[rc];
y = A[cr];
B[rc] = y;
B[cr] = x;
}
}
}
/* 3x3 matrix multiply
* C = A B
* C may occupy the same storage as either A or B.
*/
mmpy3( A, B, C )
double A[3][3], B[3][3], C[3][3];
{
double ans[3][3];
double s;
int i, r, c, k;
for( r=0; r<3; r++ )
{
for( c=0; c<3; c++ )
{
s = 0.0;
for ( i=0; i<3; i++ )
s += A[r][i] * B[i][c];
ans[r][c] = s;
}
}
for( r=0; r<3; r++ )
{
for( c=0; c<3; c++ )
{
C[r][c] = ans[r][c];
}
}
}
/* Construct the matrix that represents the composite of
* successive rotations by the three Euler angles:
* first by an angle phi about the z axis,
* second by an angle theta about the new x axis,
* third by an angle psi about the final z axis.
* The input array e[] contains the three angles in the order
* phi, theta, psi. The 3x3 output matrix M[][] is the
* composite transformation of the three rotations in
* Cartesian coordinates.
* The matrix elements have been written out directly
* in trigonometric form so that the derivation of the
* inverse function MtoE() will be clear.
*/
EtoM( e, M )
double e[3];
double M[3][3];
{
double a, b;
double sinpsi, cospsi, sinth, costh, sinphi, cosphi;
sinpsi = sin(e[2]);
cospsi = cos(e[2]);
sinth = sin(e[1]);
costh = cos(e[1]);
sinphi = sin(e[0]);
cosphi = cos(e[0]);
a = costh*sinphi;
b = costh*cosphi;
M[0][0] = cospsi*cosphi - a*sinpsi;
M[0][1] = cospsi*sinphi + b*sinpsi;
M[0][2] = sinpsi*sinth;
M[1][0] = -sinpsi*cosphi - a*cospsi;
M[1][1] = -sinpsi*sinphi + b*cospsi;
M[1][2] = cospsi*sinth;
M[2][0] = sinth*sinphi;
M[2][1] = -sinth*cosphi;
M[2][2] = costh;
}
/* Deduce the three Euler angles e[]
* from the input coordinate rotation matrix M[][].
* This is done by trigonometry from the elements of M.
*
* Since
* M[2][1] = -sin(theta) * cos(phi)
* M[2][0] = sin(theta) * sin(phi),
* then phi = arctan( M[2][0]/M[2][1].
*
* Similarly,
* M[0][2] = sin(psi) * sin(theta)
* M[1][2] = cos(psi) * sin(theta),
* so psi = arctan( M[0][2]/M[1][2] ).
*
* Finally,
* M[2][2] = cos(theta)
* M[1][2]/cos(psi) = sin(theta),
* which gives the arctangent of theta.
*/
MtoE( M, e )
double M[3][3], e[];
{
double a, b, phi, theta, psi;
double zatan2(), fabs(), sqrt(), sin(), cos();
phi = zatan2( -M[2][1], M[2][0] );
a = M[0][2];
b = M[1][2];
psi = zatan2( b, a );
if( fabs(a) > fabs(b) )
a = a/sin(psi);
else
a = b/cos(psi);
theta = zatan2( M[2][2], a );
e[0] = phi;
e[1] = theta;
e[2] = psi;
}
/* zatan2()
*
* Quadrant correct inverse circular tangent
*
*
*
* SYNOPSIS:
*
* double x, y, z, zatan2();
*
* z = zatan2( x, y );
*
*
*
* DESCRIPTION:
*
* Returns radian angle between 0 and +2pi whose tangent
* is y/x.
*
*
*
* ACCURACY:
*
* See atan.c.
*
*/
/*
Cephes Math Library Release 2.0: April, 1987
Copyright 1984, 1987 by Stephen L. Moshier
Direct inquiries to 30 Frost Street, Cambridge, MA 02140
Certain routines from the Library, including this one, may
be used and distributed freely provided this notice is retained
and source code is included with all distributions.
*/
/* include "prec.h" */
double zatan2( x, y )
double x, y;
{
double z, w;
short code;
double atan();
code = 0;
if( x < 0.0 )
code = 2;
if( y < 0.0 )
code |= 1;
if( x == 0.0 )
{
if( code & 1 )
return( 1.5*PI );
if( y == 0.0 )
return( 0.0 );
return( 0.5*PI );
}
if( y == 0.0 )
{
if( code & 2 )
return( PI );
return( 0.0 );
}
switch( code )
{
case 0: w = 0.0; break;
case 1: w = 2.0 * PI; break;
case 2:
case 3: w = PI; break;
}
z = atan( y/x );
return( w + z );
}
#else
extern double J2000, STR, DTR, RTD, PI;
#endif /* SALONE */
/* Subroutine to precess orbital elements
* from Julian date JD1 to Julian date JD2.
* The input elements, corresponding to precessional epoch JD1, are
* e[0] = node
* e[1] = inclination
* e[2] = arg perihelion
*/
oprecess( JD1, JD2, e )
double JD1, JD2, e[];
{
double x, max;
double P[3][3], Q[3][3];
/* Find the precession matrix to go from JD2 to JD1.
*/
epmat( JD1, P ); /* J2000 to JD1 */
epmat( JD2, Q ); /* J2000 to JD2 */
mtransp( Q, Q ); /* transpose = JD2 to J2000 */
mmpy3( P, Q, P ); /* JD2 to J2000 to JD1 */
EtoM( e, Q ); /* Convert input Euler angles to rotation matrix */
/* Calculate the composite rotation
* ecliptic JD2 -> ecliptic JD1 -> orbit.
*/
mmpy3( Q, P, Q );
/* Find the Euler angles of the result
*/
MtoE( Q, e );
}
/* The following subprogram, epmat( JD, P ),
* constructs the precession matrix in ecliptic coordinates
* to go from the epoch J2000.0 to the date JD. Output P is the
* 3x3 rotation matrix. To go in the opposite direction,
* from JD to J2000.0, the required matrix is just the transpose of P.
* Note that the obliquity of date is not required here since the
* coordinates are ecliptic, not equatorial.
*/
/* Accumulated precession in longitude. Coefficients are from:
* J. Laskar, "Secular terms of classical planetary theories
* using the results of general theory," Astronomy and Astrophysics
* 157, 59070 (1986).
*/
static double pAcof[] = {
-8.66e-10, -4.759e-8, 2.424e-7, 1.3095e-5, 1.7451e-4, -1.8055e-3,
-0.235316, 0.07732, 111.1971, 50290.966 };
/* Node and inclination of the earth's orbit computed from
* Laskar's data as explained in the following paper:
* P. Bretagnon and G. Francou, "Planetary theories in rectangular
* and spherical variables. VSOP87 solutions," Astronomy and
* Astrophysics 202, 309-315 (1988).
*/
static double nodecof[] = {
6.6402e-16, -2.69151e-15, -1.547021e-12, 7.521313e-12, 6.3190131e-10,
-3.48388152e-9, -1.813065896e-7, 2.75036225e-8, 7.4394531426e-5,
-0.042078604317, 3.052112654975 };
static double inclcof[] = {
1.2147e-16, 7.3759e-17, -8.26287e-14, 2.503410e-13, 2.4650839e-11,
-5.4000441e-11, 1.32115526e-9, -5.998737027e-7, -1.6242797091e-5,
0.002278495537, 0.0 };
epmat( JD, P )
double JD;
double P[];
{
double T, s, pA, i, Omega;
double e[3];
double *p;
int j;
T = (JD - J2000)/365250.0; /* thousands of years from J2000.0 */
/* Accumulated precession in longitude
*/
p = pAcof;
pA = *p++;
for( j=0; j<9; j++ )
pA = pA * T + *p++;
pA *= STR * T;
/* Node of the moving ecliptic on the J2000 ecliptic.
*/
p = nodecof;
Omega = *p++;
for( j=0; j<10; j++ )
Omega = Omega * T + *p++;
/* Inclination of the moving ecliptic to the J2000 ecliptic.
*/
p = inclcof;
i = *p++;
for( j=0; j<10; j++ )
i = i * T + *p++;
/* Set up the Euler angles */
e[0] = Omega;
e[1] = i;
e[2] = -(Omega + pA );
/* Construct the rotation matrix
* to go from J2000 to JD
*/
EtoM( e, P );
}